package com.test;

import java.util.Arrays;

/**
 * 堆排序
 *
 * 时间复杂度o(nlogn)  空间复杂度o(1)
 *
 * 没有最好与最坏的区别 时间复杂度都是o(nlogn) 不是很稳定的算法
 *
 * 说明：
 *具有n个元素的序列（h1,h2,...,hn),当且仅当满足（hi>=h2i,hi>=2i+1）或（hi<=h2i,hi<=2i+1）(i=1,2,...,n/2)时称之为堆。
 * 在这里只讨论满足前者条件的堆。由堆的定义可以看出，堆顶元素（即第一个元素）必为最大项（大顶堆）。完全二叉树可以很直观地表示堆的结构。
 * 堆顶为根，其它为左子树、右子树。初始时把要排序的数的序列看作是一棵顺序存储的二叉树，调整它们的存储序，使之成为一个堆，
 * 这时堆的根节点的数最大。然后将根节点与堆的最后一个节点交换。然后对前面(n-1)个数重新调整使之成为堆。
 * 依此类推，直到只有两个节点的堆，并对它们作交换，最后得到有n个节点的有序序列。
 * 从算法描述来看，堆排序需要两个过程，一是建立堆，二是堆顶与堆的最后一个元素交换位置。
 * 所以堆排序有两个函数组成。一是建堆的渗透函数，二是反复调用渗透函数实现排序的函数。
 *
 *
 * 对于大数据的处理呢，如果对100亿条数据选择Topk数据，选择快速排序好还是堆排序好？
 * 答案是只能用堆排序。
 * 堆排序只需要维护一个k大小的空间，即在内存开辟k大小的空间。而快速排序需要开辟能存储100亿条数据的空间
 *
 * Created by abing on 2015/11/26.
 */
public class SuanFaStack {

    public static void main(String[] args){
        int[] a = {3,1,4,6,2,43,21,65,22,44,88,11};

        headSort(a);

        for (int i : a){
            System.out.print(i + " ");
        }

    }


    public static void headSort(int[] arr){
        int arrlength = arr.length;
        for (int i = 0 ; i < arrlength - 1 ; i++){
            buildMaxHeap(arr, arrlength - 1 - i);
            swap(arr, 0, arrlength - 1 - i);
            System.out.println(Arrays.toString(arr));
        }
    }

    public static void swap(int[] arr , int i , int j){
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

    public static void buildMaxHeap(int[] data , int lastIndex){
        for (int i = (lastIndex-1)/2 ; i >= 0 ; i--){
            int k = i;
            while (k*2 + 1 <= lastIndex){
                int biggerIndex = 2*k + 1;
                if (biggerIndex < lastIndex){
                    if (data[biggerIndex] < data[biggerIndex+1]){
                        biggerIndex++;
                    }
                }

                if (data[k] < data[biggerIndex]){

                    swap(data , k , biggerIndex);
                    k = biggerIndex;
                }else {
                    break;
                }

            }

        }
    }
}
